using System;
using BT.Sdk;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Collections.ObjectModel;


namespace cmdPhone
{
    /// <summary>
    /// The Phone class will make the actual API calls to the BT SDK.
    /// </summary>
    class Phone
    {
        BT.Sdk.Core.UserToken sessionID; //Keeps the sessionID of a successfully logged user into WLA

        protected BT.Sdk.Core.UserToken SessionID
        {
            get { return sessionID; }
            set { sessionID = value; }
        }

        string userID; //keeps email(uid) of a WLA logged in user


        #region White Label Authentication(WLA) related methods (WLAuthentication is no longer required for calling any of the services)

        /// <summary>
        /// login into WLA
        /// </summary>
        /// <param name="uid">UserID</param>
        /// <param name="password">Password</param>
        public bool login(string uid, string password)
        {

            BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager authentication = new BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager();

            try
            {
                SessionID = authentication.Login(uid, password);
                userID = uid;
                return true;

            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }

        }
        


        /// <summary>
        /// Changes password for a given account
        /// </summary>
        /// <param name="email">Account email</param>
        /// <param name="password">Current Password</param>
        /// <param name="newPassword">New Password</param>
        /// <returns></returns>
        public bool changePassword(string email, string password, string newPassword)
        {
            try
            {
                BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager auth = new BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager();
                auth.ChangeUserPassword(email, password, newPassword);
                return true;
            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }

        }

        /// <summary>
        /// Creates a WLA account
        /// </summary>
        /// <returns>true if account was created successfully, false otherwise</returns>
        public bool createAccount(string email)
        {
            try
            {
                BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager auth = new BT.Sdk.WhiteLabelAuthenticationCapability.WhiteLabelAuthenticationManager();
                auth.AddUser(email);
                return true;
            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }

        }



        /// <summary>
        /// Asserts whether user has logged into WLA
        /// </summary>
        /// <returns>true/false</returns>
        public bool hasSession()
        {
            return !SessionID.Equals(Guid.Empty);
        }



        #endregion WLA related methods 


        /// <summary>
        /// Connects two phones together
        /// </summary>
        /// <param name="caller">Caller's number (Phone number of the destination with the country code without double zeros. Prefixed by tel:(landline/mobile) or sip:(ip-phones) as required: e.g. tel:44200188469000)</param>
        /// <param name="callee">Callee's number (Phone number of the destination with the country code without double zeros. Prefixed by tel:(landline/mobile) or sip:(ip-phones) as required: e.g. tel:44200188469000)</param>
        /// <returns>True if no exception was thrown</returns>
        public bool voiceCall(string caller, string callee)
        {
            BT.Sdk.Session.ThirdPartyCallCapability.SessionThirdPartyCallManager voiceCall = new BT.Sdk.Session.ThirdPartyCallCapability.SessionThirdPartyCallManager();
            try
            {
                if (isValidTelNumber(ref caller) && isValidTelNumber(ref callee))
                {
                    voiceCall.MakeCall(caller, callee);
                    return true;
                }
                else
                {
                    return false;
                }

            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }

        }



        /// <summary>
        /// Connects two or more phones together 
        /// Phone numbers should be entered with the country code without double zeros. Prefixed by tel:(landline/mobile) or sip:(ip-phones) as required: e.g. tel:44200188469000
        /// </summary>
        /// <param name="phones">
        /// 0=phoneNumber1 2=phoneNumber2 [3=phoneNumber3]...
        /// Incorrect numbers will be ignored
        /// </param>
        public bool conferenceCall(Collection<string> phones)
        {
            try
            {
                BT.Sdk.Session.ConferencingCapability.SessionConferencingManager confCallManager = new BT.Sdk.Session.ConferencingCapability.SessionConferencingManager();
                BT.Sdk.Session.ConferencingCapability.ConferenceCall conf = confCallManager.CreateConference();
                foreach (var phone in phones)
                {
                    conf.InviteParticipant(phone);
                }
                return true;
            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }
        }



        /// <summary>
        /// Send SMS messages
        /// </summary>
        /// <param name="Destination">Phone number of the destination with the country code without double zeros. Prefixed by tel:(landline/mobile) or sip:(ip-phones) as required: e.g. tel:44200188469000</param>
        /// <param name="message">Actual message content</param>
        /// <param name="sender">Sender, cannot be only numbers or an empty string</param>
        /// <returns>True if message has been sent successfully, false otherwise</returns>
        public virtual bool sendTextMessage(string Destination, string message, string sender)
        {
            BT.Sdk.Messaging.OneWayCapability.MessagingOneWayManager Sms = new BT.Sdk.Messaging.OneWayCapability.MessagingOneWayManager();
            try
            {
                if (isValidTelNumber(ref Destination))
                {
                    Sms.SendMessage(Destination, sender, message);
                    return true;
                }
                else
                {
                    return false;
                }

            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }

        }



        /// <summary>
        /// If your cert has an inbound SMS keyword associated with it, or if you are renting an inbound SMS number you can check whether you have any inbound SMSs by calling this method 
        /// </summary>
        /// <param name="keyword">
        /// Inbound SMS keyword associated with your cert(You will need to ask for it at web21c.bt.com as it is not provided by default). 
        /// If you are renting a whole inbound SMS number simply pass an empty string and you will received all SMSs sent to that number not only the ones matching a given key
        /// </param>
        /// <returns></returns>
        public Collection<BT.Sdk.Messaging.InboundCapability.Message> readInboundSMS(string keyword)
        {
            BT.Sdk.Messaging.InboundCapability.MessagingInboundManager inSMS = new BT.Sdk.Messaging.InboundCapability.MessagingInboundManager();

            if (!String.IsNullOrEmpty(keyword))
            {
                return inSMS.GetReceivedMessages(keyword);
            }
            else //if keyword is empty (i.e. you have rented an inbound sms)
            {
                return inSMS.GetReceivedMessages();
            }

        }



        /// <summary>
        /// Removes all your inbound SMS messages
        /// </summary>
        /// <param name="keyword">
        /// Inbound SMS keyword associated with your cert(You will need to ask for it at web21c.bt.com as it is not provided by default). 
        /// If you are renting a whole inbound SMS number simply pass an empty string and you will flush all SMSs sent to that number not only the ones matching a given key
        /// </param>
        /// <returns></returns>
        public bool flushInboundSMSs(string keyword)
        {
            try
            {
                BT.Sdk.Messaging.InboundCapability.MessagingInboundManager inSMS = new BT.Sdk.Messaging.InboundCapability.MessagingInboundManager();

                Collection<BT.Sdk.Messaging.InboundCapability.Message> messages;

                if (!String.IsNullOrEmpty(keyword))
                {
                    messages = inSMS.GetReceivedMessages(keyword);
                }
                else // if keyword is empty (i.e. you have rented an inbound sms)
                {
                    messages = inSMS.GetReceivedMessages();
                }

                foreach (var msg in messages)
                {
                    inSMS.ClearReceivedMessages(msg.MessageId);
                }

                return true;
            }
            catch (Exception ex)
            {
                Interaction.dealWithException(ex);
                return false;
            }
        }



        /// <summary>
        /// Asserts whether a given phone number has a valid format
        /// If invalid this method will attempt to correct the format
        /// Example of invalid phones that this method will correct:
        ///     tel:0044200188469000 (double zeros)
        ///     44200188469000 (no protocol, missing tel:)
        ///     0044200188469000 (double zeros and missing tel:)
        ///     
        /// todo: This method atm will only accept valid "tel:" (non SIP) phone numbers 
        ///       needs to be updated to handle SIP endpoints as well
        /// </summary>
        /// <param name="val">End point address: phone number or SIP address</param>
        /// <returns>true if valid (or corrected), false otherwise</returns>
        public bool isValidTelNumber(ref string val)
        {
            string validPhoneRegex = Resources.regex_for_valid_phone_with_protocol;
            if (Regex.Match(val, validPhoneRegex).Success)
            {
                return true;
            }
            else
            {
                val = removePhoneProtocol(val);

                val = removeTrailingzeros(val);

                validPhoneRegex = Resources.regex_for_valid_phone_no_protocol;
                if (Regex.Match(val, validPhoneRegex).Success)
                {
                    val = "tel:" + val;
                    return true;
                }

                return false;
            }

        }

        /// <summary>
        /// Removes all prefixed zeros from a given number using recursion
        /// </summary>
        /// <param name="number">001234</param>
        /// <returns>1234</returns>
        private string removeTrailingzeros(string number) 
        {
            if (number.StartsWith("0"))
            {
                number = number.Remove(0, 1);
                number = removeTrailingzeros(number);
                return number;
            }
            else
            {
                return number;
            } 
        }

        /// <summary>
        /// Removes the phone protocol(tel:,sip:) if present
        /// </summary>
        /// <param name="number">tel:44791868916</param>
        /// <returns>44791868916</returns>
        private string removePhoneProtocol(string number) 
        {
            if (number.StartsWith("tel:") || number.StartsWith("sip:")) 
            {
                number = number.Remove(0, 4);
            }

            return number;
        }
       

    }
}
